package com.it.data.base

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.it.common.bean.CommonBean
import com.it.common.bean.ResultBean
import com.it.common.utils.LogUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
import retrofit2.HttpException
import java.io.IOException

/**
 *  @Description：ViewModel基类
 *  @author：weishixiong
 *  @date：2023/3/28 19:02
 *
 */
abstract class BaseViewModel : ViewModel() {

    val TAG = javaClass.simpleName


    /**
     * 查询 相关的http请求 可以调用该函数
     * @param request [@kotlin.ExtensionFunctionType] SuspendFunction1<CoroutineScope, Resp<T>>
     * @param resp Function1<CommonBean<T>, Unit>
     * @param error Function1<Throwable, Unit>
     */
    fun <T> requestQuery(
        request: suspend CoroutineScope.() -> ResultBean<T>,
        resp: (CommonBean<T>) -> Unit,
    ) {
        requestSimple(request, resp = {
            resp.invoke(CommonBean(it.data, it.data != null, it.message))
        }, error = {
            resp.invoke(CommonBean(null, false, it.message))
        })

    }

    /**
     * 提交 关的http请求 可以调用该函数
     * @param request [@kotlin.ExtensionFunctionType] SuspendFunction1<CoroutineScope, Resp<T>>
     * @param resp Function1<CommonBean<T>, Unit>
     * @param error Function1<Throwable, Unit>
     */
    fun <T> requestCommit(
        request: suspend CoroutineScope.() -> ResultBean<T>,
        resp: (CommonBean<T>) -> Unit,
    ) {
        requestSimple(request, resp = {
            Log.d(TAG, "requestCommit: resp ${it}")
            resp.invoke(
                CommonBean(
                    data = it.data,
                    result = it.code == 200,
                    msg = "${it.code}-${it.message}"
                )
            )
        }, error = {
            Log.d(TAG, "requestCommit: error ${it}")
            resp.invoke(CommonBean(data = null, result = false, msg = handleException(it)))
        })


    }

    /**
     * 通用请求
     * 如果不想用以上两种封装好的函数，
     * 也可以使用一下通用的请求，会直接获取到http返回的原始数据，和异常信息
     * @param request [@kotlin.ExtensionFunctionType] SuspendFunction1<CoroutineScope, Resp<T>>
     * @param resp Function1<Resp<T>, Unit>
     * @param error Function1<Throwable, Unit>
     */
    fun <T> requestSimple(
        request: suspend CoroutineScope.() -> ResultBean<T>,
        resp: (ResultBean<T>) -> Unit,
        error: (Throwable) -> Unit = {},
    ) {
        viewModelScope.launch {
            flow { emit(request()) }    //网络请求
                .flowOn(Dispatchers.IO)  //指定网络请求的线程
                .catch {  //异常捕获处理
                    LogUtil.d(TAG, Log.getStackTraceString(it))
                    error.invoke(it)
                }
                //数据请求返回处理  emit(block()) 返回的数据
                .collect {
                    resp.invoke(it)
                }
        }

    }

    /**
     * 数据库查询操作
     * @param request [@kotlin.ExtensionFunctionType] SuspendFunction1<CoroutineScope, T>
     * @param resp Function1<Resp<T>, Unit>
     * @param error Function1<Throwable, Unit>
     */
    fun <T> requestDBQuery(
        request: suspend CoroutineScope.() -> T,
        resp: (CommonBean<T>) -> Unit
    ) {
        viewModelScope.launch {
            flow { emit(request()) }    //网络请求
                .flowOn(Dispatchers.IO)  //指定网络请求的线程
                .catch {  //异常捕获处理
                    LogUtil.d(TAG, Log.getStackTraceString(it))
                    resp.invoke(CommonBean(null, false, it.message))
                }
                //数据请求返回处理  emit(block()) 返回的数据
                .collect {
                    resp.invoke(CommonBean(it, true, "success"))
                }
        }

    }

    /**
     * 解析异常类型
     * @param e Throwable
     * @return String
     */
    private fun handleException(e: Throwable): String {
        Log.d(TAG, "handleException: ${e}")
        return when (e) {
            is IOException -> {
                return "网络异常，请联系管理员:  ${e.message}"
            }

            is HttpException -> {
                // 500,401  登录信息验证失败，请重试
                // 处理HTTP异常（需要自定义HttpException）
                if (e.code() == 401) {
                    return "登录信息验证失败，请重试"
                } else if (e.code() == 500) {
                    return "系统异常，请联系管理员"
                } else {
                    return "网络异常，请联系管理员: ${e.code()} - ${e.message()}"
                }
            }

            else -> {
                // 处理其他异常
                return "网络异常，请联系管理员:  ${e.message}"
            }
        }
    }

    /**
     * 数据库提交操作
     * @param request [@kotlin.ExtensionFunctionType] SuspendFunction1<CoroutineScope, T>
     * @param resp Function1<CommonBean<T>, Unit>
     */
    fun <T> requestDBCommit(
        request: suspend CoroutineScope.() -> T,
        resp: (CommonBean<T>) -> Unit
    ) {
        viewModelScope.launch {
            flow { emit(request()) }    //网络请求
                .flowOn(Dispatchers.IO)  //指定网络请求的线程
                .catch {  //异常捕获处理
                    LogUtil.d(TAG, Log.getStackTraceString(it))
                    resp.invoke(CommonBean(null, false, it.message))
                }
                //数据请求返回处理  emit(block()) 返回的数据
                .collect {
                    resp.invoke(CommonBean(it, true, "success"))
                }
        }

    }
}